﻿using Orleans;
using Orleans.Concurrency;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace iTool.ClusterComponent
{
    public interface IKeyValueReader : iToolServiceWithStringKey
    {
        Task<string> GetAsync();
        Task SetAsync(string payload);
        Task RemoveAsync();
    }

    [Reentrant]
    public class KeyValueReader : iToolServiceBase<KeyValueState, KeyValueExcuteBase>, IKeyValueReader
    {
        //Guid guid;
        //public KeyValueReader() 
        //{
        //    guid = Guid.NewGuid();
        //}
        public KeyValueReader() : base(100) { }

        public async Task<string> GetAsync()
        {
            return await Task.FromResult(this.State.Value);
        }
        public Task RemoveAsync()
        {
            this.State.Value = string.Empty;
            this.RaiseEvent(new KeyValueRemove());
            return Task.CompletedTask;
        }

        public Task SetAsync(string payload)
        {
            this.State.Value = payload;
            this.RaiseEvent(new KeyValueSet { Payload = payload });
            return Task.CompletedTask;
        }

        public async override Task<KeyValuePair<int, KeyValueState>> ReadStateFromStorage()
        {
            //Console.WriteLine("ReadStateFromStorage:{0}-{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), guid);
            var service = this.GrainFactory.GetGrain<IKeyValueStorageService>(this.GetPrimaryKeyString());
            var state = await service.GetStateAsync();
            return new KeyValuePair<int, KeyValueState>(state.Version, state);
        }

        public async override Task<bool> ApplyUpdatesToStorage(IReadOnlyList<KeyValueExcuteBase> updates, int expectedversion)
        {
            var service = this.GrainFactory.GetGrain<IKeyValueStorageService>(this.GetPrimaryKeyString());
            var serviceVersion = await service.GetVersionAsync();
            //Console.WriteLine("ApplyUpdatesToStorage:expectedversion-{0}-{1}-{2}-{3}", expectedversion, serviceVersion, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), guid);
            if (expectedversion < serviceVersion)
            {
                return false;
            }
            return true;
        }

        protected override void NotifyStateChanged(IGrainFactory iGrainFactory)
        {
            //var service = iGrainFactory.GetGrain<IKeyValueStorageService>(this.GetPrimaryKeyString());
            //var payload = await service.GetAsync();
            //this.State.Value = payload;
        }

        protected async override void TransitionState(KeyValueState state, KeyValueExcuteBase @event)
        {
            //Console.WriteLine("TransitionState:{0}-{1}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), guid);
            var service = this.GrainFactory.GetGrain<IKeyValueStorageService>(this.GetPrimaryKeyString());
            if (@event is KeyValueSet set)
            {
                await service.SetAsync(set.Payload);
            }
            else
            {
                //state.Value = string.Empty;
                await service.RemoveAsync();
            }
        }
    }


    public class KeyValueExcuteBase 
    {

    }

    public class KeyValueRemove : KeyValueExcuteBase
    {

    }

    public class KeyValueSet : KeyValueExcuteBase
    {
        public string Payload { get; set; }
    }
}
